package com.tanger.common.files;

import com.aliyun.oss.model.ObjectMetadata;
import com.tanger.common.helper.ContentTypeHelper;
import com.tanger.common.utils.StringUtil;
import org.apache.commons.io.FileUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class FilesObject {


    private volatile static FilesObject filesObject;// 缓存实例对象


    /**
     * 采用单例模式获取缓存对象实例
     *
     * @return
     */
    public static FilesObject getInstance() {
        if (null == filesObject) {
            synchronized (FilesObject.class) {
                if (null == filesObject) {
                    filesObject = new FilesObject();
                }
            }
        }
        return filesObject;
    }

    /**
     * 上传文件
     * 支持OSS、MINIO、LOCAL
     *
     * @param f
     * @param key LOCAL时，此值应该为“{"/usr/local/src/", "map", "00230021", "123456.png"}”
     * @return
     */
    public boolean putObject(File f, String... key) {

        if (StringUtil.isNull(FilesConfig.type)) return false;

        try {
            InputStream in = new FileInputStream(f);
            return putObject(in, key);
        }catch (Exception e){
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 上传文件
     *
     * @param in  文件流
     * @param key 文件路径，带路径和文件名称
     *            LOCAL时，此值应该为“{"/usr/local/src/", "map", "00230021", "123456.png"}”
     *
     * @return boolean
     */
    public boolean putObject(InputStream in, String... key) {
        if (StringUtil.isNull(FilesConfig.type)) return false;

        if (FilesConfig.type.equals("OSS")) {
            return new OSSObject().putObject(key[0], in);
        } else if (FilesConfig.type.equals("MINIO")) {
            return new MinioObject().putObject(key[0], in);
        } else if (FilesConfig.type.equals("LOCAL")) {
            //创建目录（key的结构为   {"/usr/local/src/", "map", "00230021", "123456.png"}）
            int len = key.length, i = 0;
            //定义最终的目录
            String fileDirPath = key[0];
            for (String k : key) {
                //从索引1开始至倒数第一个
                if (i == 0 || i >= len - 1) {
                    i++;
                    continue;
                }
                File file = new File(fileDirPath, k);
                if (!file.exists()) file.mkdirs();
                fileDirPath = file.toString();
                i++;
            }
            if (StringUtils.isEmpty(fileDirPath)) return false;
            try {
                File targetFile = new File(fileDirPath, key[len - 1]);
                if (targetFile.exists())  targetFile.delete();
                targetFile.createNewFile();
                inputstreamtofile(in, targetFile);
                return true;
            } catch (Exception e) {
                e.printStackTrace();
                return false;
            }
        } else {
            return false;
        }
    }

    /**
     * OSS上传
     * @param faceImage
     * @return
     * @throws Exception
     */
    public String uploadFile(MultipartFile faceImage) throws Exception {
        String fileName = faceImage.getOriginalFilename();
        String extension = "";
        if (fileName.indexOf(".") != -1) {
            extension = fileName.substring(fileName.indexOf(".")).toLowerCase();
        }
        int rand = (int) ((Math.random() * 9 + 1) * 1000);
        String originalImageName = fileName.substring(0,fileName.indexOf("."))+rand + extension;
        try {
            final String key = FilesConfig.serverUrl + originalImageName;
            final ObjectMetadata meta = new ObjectMetadata();

            meta.setContentLength(faceImage.getSize());
            meta.setContentType(ContentTypeHelper.getcontentType(fileName.substring(fileName.lastIndexOf("."))));
            new OSSObject().putObject(key, faceImage.getInputStream(), meta);
        } catch (Exception e) {
            e.printStackTrace();
            return "error:"+e.getMessage();
        }
        return originalImageName;
    }

    /**
     * 上传二维码
     * @param faceImage
     * @param extension
     * @return
     * @throws Exception
     */
    public String uploadCode(final BufferedImage faceImage, String extension) throws Exception {
        String originalImageName = System.currentTimeMillis() + extension;
        String key = FilesConfig.dir + originalImageName;

        try {
            final ObjectMetadata objectMeta = new ObjectMetadata();
            if (extension.toLowerCase().equals(".pdf")) {
                objectMeta.setContentType("application/pdf");
            } else {
                objectMeta.setContentType("image/png");
            }

            final ObjectMetadata meta = new ObjectMetadata();
            meta.setContentType(ContentTypeHelper.getcontentType(originalImageName.substring(originalImageName.lastIndexOf("."))));
            ByteArrayOutputStream out = new ByteArrayOutputStream();
            ImageIO.write(faceImage, "jpg", out);
            InputStream is = new ByteArrayInputStream(out.toByteArray());
            meta.setContentLength(is.available());
            new OSSObject().putObject(key, is, meta);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return originalImageName;
    }

    /**
     * <p>标题： Minio文件删除</p>
     * <p>说明： 如果文件存在，则直接删除；如果文件不存在，则不做处理</p>
     *
     * @param key 文件路径/文件名
     * @return true:文件删除成功	false:文件删除失败
     */
    public boolean deleteObject(String ... key) {
        if (StringUtil.isNull(FilesConfig.type)) return false;

        if (FilesConfig.type.equals("OSS")) {
            return new OSSObject().deleteObject(key[0]);
        } else if (FilesConfig.type.equals("MINIO")) {
            return new MinioObject().deleteObject(key[0]);
        } else if (FilesConfig.type.equals("LOCAL")) {
            //校验目录（key的结构为   {"/usr/local/src/", "map", "00230021", "123456.png"}）
            int len = key.length, i = 0;
            //定义最终的目录
            String fileDirPath = key[0];
            for (String k : key) {
                //从索引1开始至倒数第一个
                if (i == 0 || i >= len - 1) {
                    i++;
                    continue;
                }
                File file = new File(fileDirPath, k);
                if (!file.exists()) return false;
                fileDirPath = file.toString();
                i++;
            }
            if (StringUtils.isEmpty(fileDirPath)) return false;
            File targetFile = new File(fileDirPath, key[len - 1]);
            if (!targetFile.exists()) return false;
            return targetFile.delete();
        } else {
            return false;
        }
    }

    /**
     * 获取目录下的所有文件 (非递归)
     *
     * @param srcKey
     * @return
     */
    public List<String> getDirFiles(String ... srcKey) {

        if (StringUtil.isNull(FilesConfig.type)) return new ArrayList<>();

        if (FilesConfig.type.equals("OSS")) {
            return new OSSObject().getFiles(srcKey[0]);
        } else if (FilesConfig.type.equals("MINIO")) {
            return new MinioObject().getFiles(srcKey[0]);
        } else if (FilesConfig.type.equals("LOCAL")) {
            //校验目录（key的结构为   {"/usr/local/src/", "map", "00230021", "123456.png"}）
            int len = srcKey.length, i = 0;
            //定义最终的目录
            String fileDirPath = srcKey[0];
            for (String k : srcKey) {
                //从索引1开始至倒数第一个
                if (i == 0 || i >= len) {
                    i++;
                    continue;
                }
                File file = new File(fileDirPath, k);
                if (!file.exists()) return null;
                fileDirPath = file.toString();
                i++;
            }
            if (StringUtils.isEmpty(fileDirPath)) return null;

            return Arrays.asList(new File(fileDirPath).list());
        } else {
            return new ArrayList<>();
        }
    }

    /**
     * <p>标题：OSS文件复制</p>
     * <p>说明： TODO</p>
     *
     * @param srcKey  原文件位置
     * @param destKey 复制后文件位置
     * @version 1.0  2015年9月5日 下午5:21:19
     * @return true：成功	false：失败
     */
    public boolean copyObject(String srcKey, String destKey, String ... dirs) {
        return copyObjectDel(srcKey, destKey, false, dirs);
    }

    /**
     * <p>标题：OSS文件复制 </p>
     * <p>说明： 复制成功后删除原文件</p>
     *
     * @param srcKey  原文件位置
     * @param destKey 复制后文件位置
     * @version 1.0  2015年9月5日 下午5:21:19
     * @return true：成功	false：失败
     */
    public boolean copyObjectDel(String srcKey, String destKey, String ... dirs) {
        return copyObjectDel(srcKey, destKey, true, dirs);
    }

    private boolean copyObjectDel(String srcKey, String destKey, boolean isDelSrc, String ... dirs) {
        if (FilesConfig.type.equals("OSS")) {
            if(isDelSrc) return new OSSObject().copyObjectDel(srcKey, destKey);
            return new OSSObject().copyObject(srcKey, destKey);
        } else if (FilesConfig.type.equals("MINIO")) {
            if(isDelSrc) return new MinioObject().copyObjectDel(srcKey, destKey);
            return new MinioObject().copyObject(srcKey, destKey);
        } else if (FilesConfig.type.equals("LOCAL")) {
            //校验目录（key的结构为   {"/usr/local/src/", "map", "00230021", "123456.png"}）
            int len = dirs.length, i = 0;
            //定义最终的目录
            String fileDirPath = dirs[0];
            for (String k : dirs) {
                //从索引1开始至倒数第一个
                if (i == 0 || i >= len) {
                    i++;
                    continue;
                }
                File file = new File(fileDirPath, k);
                if (!file.exists()) return false;
                fileDirPath = file.toString();
                i++;
            }
            if (StringUtils.isEmpty(fileDirPath)) return false;

            File srcFile = new File(fileDirPath, srcKey);
            File destFile = new File(fileDirPath, destKey);
            try{

                if(!srcFile.exists()) return false;
                if(destFile.exists())destFile.delete();

                FileUtils.copyFile(srcFile, destFile);

                if(isDelSrc) srcFile.delete();

                return true;
            }catch (Exception e){
                e.printStackTrace();
                return false;
            }
        } else {
            return false;
        }
    }


    private void inputstreamtofile(InputStream ins, File file) throws IOException {
        OutputStream os = new FileOutputStream(file);
        int bytesRead = 0;
        byte[] buffer = new byte[8192];
        while ((bytesRead = ins.read(buffer, 0, 8192)) != -1) {
            os.write(buffer, 0, bytesRead);
        }
        os.close();
        ins.close();
    }
}
